#include"can_init.h"
#include"ip_can_fifo.h"
#include"can_intr_t.h"
#include"can_sys_t.h"
#include <unistd.h>
#include"ringbuffer.h"
#include "unistd.h"
#include "can_struct_t.h"

ring_buffer_t *data_frame3_buffer = NULL;
ring_buffer_t *shared_can_rx_buffer = NULL;
uint32_t total_frame_count = 0;
uint32_t channel_frame_count[6] = {0};
uint8_t buffer_config_receive[CAN_PACK_LEN];
uint8_t buffer_recv[RW_BUFFER_LEN]; //从AXIFIFO中读取数据放到里面
uint8_t buffer_read_ddr[READ_DDR_BUFFER] ;//存放从DDR中取到的数据
uint8_t buffer_sent_ddr[WR_BUFFER_LEN] ;//存放从缓冲区中读到的数据准备写到DDR中
uint8_t xor_status_calculated;

static ddr_manager_t read_ddr_message;
static ddr_manager_t write_ddr_message;
int b=0;

// Endian conversion
uint32_t swap_endian_32bit(uint32_t value)
{
    return ((value & 0xFF000000) >> 24) |
           ((value & 0x00FF0000) >> 8)  |
           ((value & 0x0000FF00) << 8)  |
           ((value & 0x000000FF) << 24);
}
// The length is 4 bytes. Perform an XOR calculation on all the previous data in units of 4 bytes.

// Read data from the DDR
int read_from_ddr(const axi_ddr_t *mem_info, uint8_t *buffer) {

    if (mem_info == NULL || buffer == NULL || mem_info->pkt_len == 0) {
    	xil_printf("mem_info == NULL || buffer == NULL || mem_info->pkt_len == 0\n\r");
        return -1;
    }

    uint8_t *src = (uint8_t *)mem_info->pack_ddr_base + DDR_READ_BASE_ADDR;
   // xil_printf("recv ddr src :%p\n\r",src);
    memcpy(buffer, src, mem_info->pkt_len);

    return 0;
}

// Write data to the DDR
int write_to_ddr(const axi_ddr_t *mem_info, const uint8_t *data) {

    if (mem_info == NULL || data == NULL || mem_info->pkt_len == 0) {
        return -1;
    }

    uint8_t *dst = (uint8_t *)mem_info->pack_ddr_base + DDR_WRITE_BASE_ADDR;
	//xil_printf("send ddr dst:%p\n\r",dst);
    memcpy(dst, data, mem_info->pkt_len);

    return 0;
}
//Create a buffer associated with CAN
int create_ring_buffers(void)
{
    for (int i = 0; i < MAX_CAN_DEVICES; i++)
    {

    	shared_can_rx_buffer = ringbuffer_create(CAN_RX_BUFFER_SIZE * MAX_CAN_DEVICES, sizeof(data_frame4_t));
    	if (shared_can_rx_buffer == NULL)
    	{
    	        xil_printf("Error: Failed to create shared ring buffer\r\n");
    	        return XST_FAILURE;
    	    }
        can_system.drv_can[i].rx_buffer = shared_can_rx_buffer;
        can_system.drv_can[i].count = 0;
    }
    return XST_SUCCESS;
}
int create_data_frame3_buffer(void)
{
    //Create a circular buffer and specify the buffer size and the element type size
    data_frame3_buffer = ringbuffer_create(DATA_FRAME3_BUFFER_SIZE, sizeof(data_frame3_t));
    if (data_frame3_buffer == NULL)
    {
        xil_printf("Error: Failed to create data_frame3 buffer\r\n");
        return XST_FAILURE;
    }

   // xil_printf("Success: Created data_frame3 buffer with size %d bytes\r\n",DATA_FRAME3_BUFFER_SIZE);

    return XST_SUCCESS;
}
//Initialize the CAN baud rate and mode
void parse_and_init_can(unsigned char *buffer, int length) {

    if (length < sizeof(data_frame1_t)) {
        return;
    }

    data_frame1_t *frame = (data_frame1_t *)buffer;

    if (frame->head != 0x499602D2) {
        return;
    }
    xil_printf("head  0x%08X\r\n", frame->head);

    uint32_t expected_checksum = calculate_xor_checksum((uint8_t *)frame, sizeof(data_frame1_t)-4);
    if (frame->xor_checksum != expected_checksum) {
        return;
    }

    xil_printf("xor_checksum  0x%08X\r\n", frame->xor_checksum);
    xil_printf("type 0x%02X\r\n",frame->type);
    if (frame->direction == 0)
    {
    	switch (frame->type) {
    	case 0x00:

    		     CAN_SetBaudRate(&can_system.drv_can[frame->ch_id], frame->baud_rate);

    		     CAN_SetMode(&can_system.drv_can[frame->ch_id], frame->mode);
    		     xil_printf("CAN%d configured: baud=%d, mode=%d\r\n", frame->ch_id, frame->baud_rate, frame->mode);
    		     axis_fifo_reset(AXIS_FIFO_BASEADDRESS);
    		    break ;

    	case 0x01:

    		break;

    	}
    }
}
//Initialize the DDR manager
int read_ddr_init() {
    read_ddr_message.base_address = DDR_READ_BASE_ADDR;
    read_ddr_message.current_address = DDR_READ_BASE_ADDR;
    read_ddr_message.total_size = DDR_BUFFER_SIZE;
    read_ddr_message.used_size = 0;
    read_ddr_message.direction = DIRECTION_UP;

    return 0;
}
int write_ddr_init() {
	write_ddr_message.base_address = DDR_WRITE_BASE_ADDR;
    write_ddr_message.current_address = DDR_WRITE_BASE_ADDR;
    write_ddr_message.total_size = DDR_BUFFER_SIZE;
    write_ddr_message.used_size = 0;
    write_ddr_message.direction = DIRECTION_DOWN;

    return 0;
}
//Read the CAN data in the buffer of the specified channel
size_t can_read_data(int channel_id, can_rx_data_t *data, size_t elements)
{
	if (channel_id < 0 || channel_id >= MAX_CAN_DEVICES)
	{
		xil_printf("Error: Invalid CAN channel ID %d\r\n", channel_id);
		return 0;
    }
	drv_can_t *can_ptr = &can_system.drv_can[channel_id];
	if (!can_ptr->rx_buffer)
	{
		xil_printf("Error: No ring buffer assigned for channel %d\r\n", channel_id);
		return 0;
    }
	return ringbuffer_get(can_ptr->rx_buffer, data, elements);
}
//
uint32_t ddr_manager_get_free_space(ddr_manager_t *manager) {
    if (manager == NULL) {
        return 0;
    }

    return manager->total_size - manager->used_size;
}
int can_ring_to_DDR(void)
{
	axi_ddr_t ddr_frame;
	uint32_t available_data;
	uint32_t bytes_to_write;
	uint32_t max_bytes_per_read = 48;
	uint32_t offset = 0;
	if (shared_can_rx_buffer != NULL && !ringbuffer_is_empty(shared_can_rx_buffer))
    {
		available_data=ringbuffer_len(shared_can_rx_buffer);

        for(uint32_t i=0; i < available_data ; i++)
        {
        	ringbuffer_get(shared_can_rx_buffer, buffer_sent_ddr + offset, 1);
        	offset +=max_bytes_per_read;

        }

        bytes_to_write = available_data * sizeof(data_frame4_t);

        ddr_frame.head=0x499601D1;
        ddr_frame.direction=0x02;
        memcpy(ddr_frame.data_type,&available_data,3);
        ddr_frame.pack_ddr_base=  write_ddr_message.used_size;
        ddr_frame.pkt_len=bytes_to_write;

		int result = write_to_ddr(&ddr_frame, buffer_sent_ddr);
		if (result != 0)
		{
			return result;
		}
		write_ddr_message.current_address = write_ddr_message.base_address + write_ddr_message.used_size;
		write_ddr_message.used_size = (write_ddr_message.used_size + bytes_to_write)%DDR_BUFFER_SIZE;


		axis_fifo_write_data(AXIS_FIFO_BASEADDRESS,(uint8_t *)&ddr_frame,sizeof(axi_ddr_t));


    }
	return 0;
}

int send_ring_to_DDR(void)
{
	axi_ddr_t axi_frame ;
	axi_ddr_t ddr_frame;
	uint32_t available_data;
	uint32_t bytes_to_write;

	uint32_t max_bytes_per_read = 48;
	uint32_t offset = 0;

	if (data_frame3_buffer != NULL && !ringbuffer_is_empty(data_frame3_buffer))
    {
		available_data=ringbuffer_len(data_frame3_buffer);

        for(uint32_t i=0; i < available_data ; i++)
        {
        	ringbuffer_get(data_frame3_buffer, buffer_sent_ddr + offset, 1);
        	offset +=max_bytes_per_read;

        }

        bytes_to_write = available_data * sizeof(data_frame4_t);

        axi_frame.head=0x499601D1;
        axi_frame.direction=0x02;
        memcpy(axi_frame.data_type,&available_data,3);
        axi_frame.pack_ddr_base=  write_ddr_message.used_size;
        axi_frame.pkt_len=bytes_to_write;

        int result = write_to_ddr(&axi_frame, buffer_sent_ddr);
    	if (result != 0)
    	{
    		return result;
    	}
    	write_ddr_message.current_address = write_ddr_message.base_address + write_ddr_message.used_size;
    	write_ddr_message.used_size = (write_ddr_message.used_size + bytes_to_write)%DDR_BUFFER_SIZE;

        axis_fifo_write_data(AXIS_FIFO_BASEADDRESS,(uint8_t *)&axi_frame,sizeof(axi_ddr_t));
    }


	return 0;
}


//DDR write function
int ddr_manager_write( const uint8_t *data, uint32_t length, uint32_t *address)
{
	static unsigned int pack_cnt = 0;
	if (data == NULL || length == 0 || address<0)
	{
		xil_printf("length:%d,address:%d\r\n",length,address);
		return -1;
	}



	axi_ddr_t mem_info;
	mem_info.head = 0x499601D1;
	mem_info.direction = (uint8_t)write_ddr_message.direction;
	memcpy(&mem_info.data_type,&pack_cnt,3);
	mem_info.pack_ddr_base = write_ddr_message.used_size;
	mem_info.pkt_len = length;

	int result = write_to_ddr(&mem_info, data);
	if (result != 0)
	{
		return result;
	}
	write_ddr_message.current_address = write_ddr_message.base_address + write_ddr_message.used_size;
	write_ddr_message.used_size = (write_ddr_message.used_size + length)%DDR_BUFFER_SIZE;

	axis_fifo_write_data(AXIS_FIFO_BASEADDRESS,(uint8_t *)&mem_info,sizeof(axi_ddr_t));
	pack_cnt++;
	return 0;
}
// DDR read function
int ddr_manager_read(uint32_t address, uint32_t length, uint8_t *buffer)
{
	if (buffer == NULL || length == 0)
	{
		xil_printf("manager == NULL || buffer == NULL || length == 0\r\n");
		return -1;
	}
	if (address < 0 || address >= read_ddr_message.total_size || address + length > read_ddr_message.total_size) {
		xil_printf("address :0x%x,base_address:0x%x,total_size:0x%x,length:%d\r\n",address,read_ddr_message.base_address,read_ddr_message.total_size,length);
		return -2;
    }

	axi_ddr_t mem_info;
	mem_info.head = 0x499601D1;
	mem_info.direction = (uint8_t)read_ddr_message.direction;
	mem_info.data_type[0] = 0x81;
	mem_info.data_type[1] = 0x00;
	mem_info.data_type[2] = 0x00;
	mem_info.pack_ddr_base = address;
	mem_info.pkt_len = length;

	int result = read_from_ddr(&mem_info, buffer);
	return result;
}

int SendFrame(drv_can_t *drv_can,  u32* Can_TxFrame)
{
    int status;


    if (drv_can == NULL ) {
        xil_printf("Error: SendFrame - Invalid parameters\r\n");
        return 2;
    }

    int channel_id = -1;
    for (int i = 0; i < MAX_CAN_DEVICES; i++) {
        if (&can_system.drv_can[i] == drv_can) {
            channel_id = i;
            break;
        }
    }

    if (channel_id == -1) {
        xil_printf("Error: SendFrame - Cannot determine CAN channel ID\r\n");
        return 3;
    }


    status = XCan_Send(&drv_can->can, Can_TxFrame);
    if (status == XST_SUCCESS)
    {

        return 0;
    }
    else
    {
    	return XST_FAILURE;
    }

}
void send_can_tx_status( int status, uint8_t ch_id) {
    static data_frame3_t status_frame =
    {
    		0x499602D2,
			0x01,
			0x80,
			0x30,
			0x00
    };
//    status_frame.direction = 0xff;
//    status_frame.type = 0xff;
    status_frame.ch_id = ch_id;
    total_frame_count = (total_frame_count == 0xFFFFFFFF) ? 0 : total_frame_count + 1;
    status_frame.total_count = total_frame_count;
    channel_frame_count[status_frame.ch_id] = (channel_frame_count[status_frame.ch_id] == 0xFFFFFFFF) ? 0 : channel_frame_count[status_frame.ch_id] + 1;
    status_frame.ch_count = channel_frame_count[status_frame.ch_id];
    status_frame.idr=tx_data.id;
    status_frame.drcr=tx_data.dlen;
    status_frame.dw1r=tx_data.dw1;
    status_frame.dw2r=tx_data.dw2;
    status_frame.states = status;
    status_frame.xor_states=xor_status_calculated;//
    status_frame.reserved2 = 0;
    status_frame.timestamp = 0;
    status_frame.xor_checksum = calculate_xor_checksum((uint8_t *)&status_frame, sizeof(data_frame3_t) - 4);

	ringbuffer_put(data_frame3_buffer,&status_frame,1);
	 b++;



}
int send_data_to_can(unsigned char *buffer, int length)
{

	int processed = 0;
	int frame_count = 0;
	uint32_t swap_can_drcr;
	if (buffer == NULL || length <= 0)
	{
	        return XST_FAILURE;
	   }
	while (processed + sizeof(data_frame2_t) <= length )
	{
		data_frame2_t *frame = (data_frame2_t *)(buffer + processed);
		if (frame->head != 0x499602D2)
		{
			xil_printf("head location failure",processed);

		      break;
		}

		uint32_t calculated_xor = calculate_xor_checksum(buffer + processed, sizeof(data_frame2_t) - 4);
		if (calculated_xor != frame->xor_checksum)
			{
				xor_status_calculated = 0;
			}
		else
		{
			xor_status_calculated = 1;
		}


		tx_data.id = frame->idr;
		tx_data.dlen = frame->drcr;
		tx_data.dw1 = frame->dw1r;
		tx_data.dw2 = frame->dw2r;
		tx_data.channel_id = frame->ch_id;
		u32 Can_TxFrame[4];
		swap_can_drcr = swap_endian_32bit(frame->drcr);
		Can_TxFrame[0] = frame->idr;
		Can_TxFrame[1] = XCan_CreateDlcValue(swap_can_drcr);
		Can_TxFrame[2] = frame->dw1r;
		Can_TxFrame[3] = frame->dw2r;
		while (XCan_IsTxFifoFull(&can_system.drv_can[tx_data.channel_id].can) == TRUE);
		int send_status = SendFrame(&can_system.drv_can[tx_data.channel_id], Can_TxFrame);



		if(!ringbuffer_is_full(data_frame3_buffer))
		{

			send_can_tx_status(send_status, tx_data.channel_id);
			frame_count++;

		}
		else
		{
			send_ring_to_DDR();
		}

		processed += sizeof(data_frame2_t);

	}
	//xil_printf("%d\n\r",frame_count);
	return frame_count;
}
//Analyze the protocol in axi_fifo, then fetch the data from DDR, and finally compare and send it to CAN.
void analyze_axi_data(unsigned char *buffer)
{
	int result;
	int count ;
//	uint_8 ddr_channel;

	axi_ddr_t *frame_t = (axi_ddr_t *)buffer;

	if(frame_t->head == 0x499601D1 && frame_t->direction ==0x00)
	{
		result = ddr_manager_read( frame_t->pack_ddr_base, frame_t->pkt_len, buffer_read_ddr);
		//xil_printf("################ result：%d  ####\r\n",result);
#if 0//DDR FANHUI
		ddr_manager_write(buffer_read_ddr,frame_t->pkt_len,frame_t->pack_ddr_base);

#endif

#if 1
		if (result !=0)
		{
			xil_printf("DDR READ FAILURE \r\n");
		}
		count = send_data_to_can(buffer_read_ddr,frame_t->pkt_len);
		if(count != (frame_t->pkt_len/48))
		{
			xil_printf("error : send data failure \r\n");
		}
		send_ring_to_DDR();
	//	xil_printf("b:%d\n\r",b);
#endif
	}
	else
	{
		xil_printf("frame ->head :0x%08x frame_t->direction :0x%08x \r\n",frame_t->head,frame_t->direction);
	}
}



int main(void)
{
	int status;

	read_ddr_init();
	write_ddr_init();
	status = system_initialize();
	if(status != XST_SUCCESS)
	{
		xil_printf("System Initialize Failed! Code: 0x%08x\r\n", status);
		return status;
	}
	//Create an independent buffer for each CAN channel
	status = create_ring_buffers();
	if (status != XST_SUCCESS)
	{
		xil_printf("Ring buffer creation failed!\r\n");
		return status;
	}
	//Create a buffer to store the status frame data
	status = create_data_frame3_buffer();
	if (status != XST_SUCCESS) {
		xil_printf("Failed to initialize data_frame3 buffer\r\n");
		return XST_FAILURE;
	}

#if 1
	while(1)
	{
		if((read_ddr_message.base_address != DDR_READ_BASE_ADDR) || (read_ddr_message.total_size != DDR_BUFFER_SIZE))
		{
			xil_printf("base_address:0x%x,total_size:0x%x\r\n",read_ddr_message.base_address,read_ddr_message.total_size);
		}
        int data_config_len = axis_fifo_read_data_len(CONFIG_FIFO_BASEADDRESS);
        int data_axi_len = axis_fifo_read_data_len(AXIS_FIFO_BASEADDRESS);
        data_axi_len = data_axi_len / 16 * 16;
#if 1   //receive CONFIG_fifo data
        if(data_config_len> 0 && data_config_len==sizeof(data_frame1_t))
        {
        	int read_length = axis_fifo_read_data(CONFIG_FIFO_BASEADDRESS, buffer_config_receive, sizeof(data_frame1_t));
        	parse_and_init_can( buffer_config_receive,read_length);
        }
#endif
#if 1
        can_ring_to_DDR();
#endif
#if 1
       // xil_printf("####RW_BUFFER_LEN:%d data_axi_len：%d  ####\r\n",RW_BUFFER_LEN, data_axi_len);
        if(data_axi_len > 0)
        {
        	int read_length = axis_fifo_read_data(AXIS_FIFO_BASEADDRESS, buffer_recv, data_axi_len);
        	for (uint16_t i = 0; i < read_length; i += CAN_PACK_LEN)
        	{

        		analyze_axi_data(buffer_recv + i);
        	}
        }


#endif
#if 1


#endif
	}
#endif
}
